/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.boot.swagger.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.iwindplus.boot.domain.vo.ServerInfoVO;
import com.iwindplus.boot.swagger.service.SwaggerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * swagger业务层接口实现类.
 *
 * @author zengdegui
 * @since 2019/8/13
 */
@Slf4j
public class SwaggerServiceImpl implements SwaggerService {

    @Override
    public ServerInfoVO getServerInfo() {
        ServerInfoVO result = new ServerInfoVO();
        List<ServerInfoVO.ApiInfoVO> apis = new ArrayList<>(10);
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = SpringUtil.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
            RequestMappingInfo info = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();
            Method method = handlerMethod.getMethod();
            final Class<?> declaringClass = method.getDeclaringClass();
            String className = declaringClass.getName();
            String methodName = method.getName();
            Tag tag = declaringClass.getAnnotation(Tag.class);
            Operation operation = handlerMethod.getMethodAnnotation(Operation.class);
            boolean flag = Objects.nonNull(tag) && (CharSequenceUtil.isNotBlank(tag.name()) || CharSequenceUtil.isNotBlank(tag.description()))
                && Objects.nonNull(operation) && (CharSequenceUtil.isNotBlank(operation.summary()) || CharSequenceUtil.isNotBlank(
                operation.description()));
            if (flag) {
                String controllerName = Optional.ofNullable(tag.name()).orElse(tag.description());
                String apiName = Optional.ofNullable(operation.summary()).orElse(operation.description());
                ServerInfoVO.ApiInfoVO.ApiInfoVOBuilder<?, ?> api = ServerInfoVO.ApiInfoVO.builder();
                api.controllerName(controllerName)
                    .className(className)
                    .methodName(methodName)
                    .requestType(this.getRequestType(info.getMethodsCondition()))
                    .apiName(apiName)
                    .hideFlag(operation.hidden());
                this.buildUrl(apis, info, api);
            }
        }
        if (CollUtil.isEmpty(apis)) {
            return result;
        }
        String serverId = SpringUtil.getProperty("spring.application.name");
        String serverName = SpringUtil.getProperty("server.servlet.application-display-name");
        result.setServerId(serverId);
        result.setServerName(serverName);
        result.setApis(apis);
        return result;
    }

    private void buildUrl(List<ServerInfoVO.ApiInfoVO> apis, RequestMappingInfo info, ServerInfoVO.ApiInfoVO.ApiInfoVOBuilder<?, ?> api) {
        // 一个方法可能对应多个url
        PatternsRequestCondition patternsCondition = info.getPatternsCondition();
        if (Objects.nonNull(patternsCondition)) {
            for (String apiUrl : patternsCondition.getPatterns()) {
                apis.add(api.apiUrl(this.getApiUrl(apiUrl)).build());
            }
        }
    }

    private String getRequestType(RequestMethodsRequestCondition methodsCondition) {
        // 如果多个，改为一个POST
        String requestType = null;
        int count = 0;
        for (RequestMethod requestMethod : methodsCondition.getMethods()) {
            requestType = requestMethod.toString();
            count++;
        }
        return requestType == null || count > 1 ? "POST" : requestType;
    }

    private String getApiUrl(String apiUrl) {
        String separator = "/";
        String separator2 = "//";
        String separator3 = "///";
        String contextPath = SpringUtil.getProperty("server.servlet.context-path");
        String requestUrl;
        if (CharSequenceUtil.isNotBlank(contextPath) && !separator.equals(contextPath)) {
            requestUrl = contextPath + apiUrl;
            if (requestUrl.contains(separator3) || requestUrl.contains(separator2)) {
                requestUrl = requestUrl.replace(separator3, separator);
                requestUrl = requestUrl.replace(separator2, separator);
            }
        } else {
            requestUrl = apiUrl;
        }
        return requestUrl;
    }

}